#include "defines.h"


int main(int argc, char * argv[]) {

	struct timeval start, end;

	long int t, x, y, z;
	int NX = atoi(argv[1]);
	int NY = atoi(argv[2]);
	int NZ = atoi(argv[3]);
	int T  = atoi(argv[4]);
		
	double (*A)[NX+2*XSTART][NY+2*YSTART][NZ+2*ZSTART] = (double (*)[NX+2*XSTART][NY+2*YSTART][NZ+2*ZSTART])malloc(sizeof(double)*(NX+2*XSTART)*(NY+2*YSTART)*(NZ+2*ZSTART)*2);
	if(NULL == A) return 0;

#ifdef CHECK
    double (*B)[NX+2*XSTART][NY+2*YSTART][NZ+2*ZSTART] = (double (*)[NX+2*XSTART][NY+2*YSTART][NZ+2*ZSTART])malloc(sizeof(double)*(NX+2*XSTART)*(NY+2*YSTART)*(NZ+2*ZSTART)*2);
	if(NULL == B) return 0;
#endif

	srand(100);

	for (x = 0; x < NX+2*XSTART; x++) {
		for (y = 0; y < NY+2*YSTART; y++) {
			for (z = 0; z < NZ+2*ZSTART; z++) {
				A[0][x][y][z] = (double) (1.0 * (rand() % 1024));
				A[1][x][y][z] = 0;
#ifdef CHECK
				B[0][x][y][z] = A[0][x][y][z];
				B[1][x][y][z] = 0;
#endif
			}
		}
	}

	gettimeofday(&start,0);
	for (t = 0; t < T; t++) {
		#pragma omp parallel for collapse(3)
		for (x = XSTART; x < NX+XSTART; x++) {
			for (y = YSTART; y < NY+YSTART; y++) {
				for (z = ZSTART; z < NZ+ZSTART; z++) {
					kernel(A);
				}
			}
		}
	}
	gettimeofday(&end,0);

	printf("GStencil/s = %f\n", ((double)NX * NY * NZ * T) / (double)(end.tv_sec - start.tv_sec + (end.tv_usec - start.tv_usec) * 1.0e-6) / 1000000000L);

#ifdef CHECK
	for (t = 0; t < T; t++) {
		for (x = XSTART; x < NX+XSTART; x++) {
			for (y = YSTART; y < NY+YSTART; y++) {
				for (z = ZSTART; z < NZ+ZSTART; z++) {
					kernel(B);
				}
			}
		}
	}
	for (x = XSTART; x < NX+XSTART; x++) {
		for (y = YSTART; y < NY+YSTART; y++) {
			for (z = ZSTART; z < NZ+ZSTART; z++) {
				if(A[T%2][x][y][z] != B[T%2][x][y][z])
					printf("Naive[%d][%d][%d] = %f, Check() = %f: FAILED!\n", x, y, z, B[T%2][x][y][z], A[T%2][x][y][z]);
			}
		}
	}
#endif	

#ifdef CHECK
	for (x = XSTART; x < NX+XSTART; x++) {
		for (y = YSTART; y < NY+YSTART; y++) {
			for (z = ZSTART; z < NZ+ZSTART; z++) {
				if(A[T%2][x][y][z] != B[T%2][x][y][z])
					printf("Naive[%d][%d][%d] = %f, Check() = %f: FAILED!\n", x, y, z, B[T%2][x][y][z], A[T%2][x][y][z]);
			}
		}
	}
#endif
}
